package com.sloth.bear.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sloth.bear.constant.CategoryType;
import com.sloth.bear.dto.entity.Category;
import com.sloth.bear.dto.entity.Todo;
import com.sloth.bear.dto.request.CategoryRequest;
import com.sloth.bear.dto.request.DragRequest;
import com.sloth.bear.dto.vo.CategoryDetailsVo;
import com.sloth.bear.dto.vo.CategoryListVo;
import com.sloth.bear.mapper.CategoryMapper;
import com.sloth.bear.service.CategoryService;
import com.sloth.bear.service.TodoService;
import com.sloth.bear.util.AssertUtils;
import com.sloth.bear.util.BaseHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    private final TodoService todoService;

    @Override
    public CategoryDetailsVo createCategory(CategoryRequest request) {
        Category category = BaseHelper.r2t(request, Category.class);

        // 验证父分类是否存在
        if (request.getParentId() != null) {
            Category parent = getById(request.getParentId());
            AssertUtils.notNull(parent, "父分类不存在");
        }

        boolean result = save(category);
        AssertUtils.isTrue(result, "分类创建失败");

        return BaseHelper.r2t(category, CategoryDetailsVo.class);
    }

    @Override
    public List<CategoryListVo> listCategory(CategoryType type) {
        List<Category> categoryList = list(Wrappers.<Category>lambdaQuery()
                .eq(type != null, Category::getType, type)
                .orderByAsc(Category::getSortNo)
                .orderByDesc(Category::getCreatedTime));

        List<CategoryListVo> categoryVoList = BaseHelper.r2t(categoryList, CategoryListVo.class);
        return buildCategoryTree(categoryVoList);
    }

    /**
     * 构建分类树形结构
     */
    private List<CategoryListVo> buildCategoryTree(List<CategoryListVo> categoryList) {
        // 根节点列表
        List<CategoryListVo> rootNodes = new ArrayList<>();

        // 按父ID分组
        Map<Long, List<CategoryListVo>> parentChildrenMap = categoryList.stream()
                .filter(category -> category.getParentId() != null)
                .collect(Collectors.groupingBy(CategoryListVo::getParentId));

        // 处理每个分类
        for (CategoryListVo category : categoryList) {
            // 设置子分类
            List<CategoryListVo> children = parentChildrenMap.get(category.getId());
            category.setChildren(Objects.requireNonNullElseGet(children, ArrayList::new));

            // 如果是根节点（parentId为null），添加到根节点列表
            if (category.getParentId() == null) {
                rootNodes.add(category);
            }
        }

        return rootNodes;
    }

    @Override
    public CategoryDetailsVo detailsCategory(Long id) {
        Category category = getById(id);
        AssertUtils.notNull(category, "分类不存在");
        return BaseHelper.r2t(category, CategoryDetailsVo.class);
    }

    @Override
    public CategoryDetailsVo updateCategory(Long id, CategoryRequest request) {
        Category category = getById(id);
        AssertUtils.notNull(category, "分类不存在");

        BeanUtils.copyProperties(request, category);
        boolean result = updateById(category);
        AssertUtils.isTrue(result, "分类更新失败");
        return BaseHelper.r2t(category, CategoryDetailsVo.class);
    }

    @Override
    public void drag(Long id, DragRequest request) {
        if ("inner".equals(request.getDropType())) {
            // 节点拖入另一个节点
            update(Wrappers.<Category>lambdaUpdate()
                    .eq(Category::getId, id)
                    .set(Category::getParentId, request.getTargetId()));
        } else if ("before".equals(request.getDropType()) || "after".equals(request.getDropType())) {
            // 节点拖到另一个节点前面：parentId等于另一个节点，顺序在另一个节点前
            Category lastNode = getById(request.getTargetId());

            update(Wrappers.<Category>lambdaUpdate()
                    .eq(Category::getId, id)
                    .set(Category::getParentId, lastNode.getParentId()));

            List<Category> docNotes = list(Wrappers.<Category>lambdaQuery()
                    .eq(Category::getType, lastNode.getType())
                    .isNull(lastNode.getParentId() == null, Category::getParentId)
                    .eq(lastNode.getParentId() != null, Category::getParentId, lastNode.getParentId())
                    .orderByAsc(Category::getSortNo)
                    .orderByDesc(Category::getCreatedTime));

            int sourceIndex = 0;
            int targetIndex = 0;
            Category dropDoc = null;
            for (int i = 0; i < docNotes.size(); i++) {
                if (docNotes.get(i).getId().equals(id)) {
                    sourceIndex = i;
                    dropDoc = docNotes.get(i);
                } else if (docNotes.get(i).getId().equals(request.getTargetId())) {
                    targetIndex = i;
                }
            }

            int index;
            if ("before".equals(request.getDropType())) {
                index = targetIndex > sourceIndex ? (targetIndex - 1) : targetIndex;
            } else {
                index = targetIndex;
            }

            docNotes.remove(sourceIndex);
            docNotes.add(index, dropDoc);

            for (int i = 0; i < docNotes.size(); i++) {
                update(Wrappers.<Category>lambdaUpdate()
                        .eq(Category::getId, docNotes.get(i).getId())
                        .set(Category::getSortNo, i));
            }
        }
    }

    @Override
    public void deleteCategory(Long id) {
        Category category = getById(id);
        AssertUtils.notNull(category, "分类不存在");

        long childCount = count(Wrappers.<Category>lambdaQuery().eq(Category::getParentId, id));
        AssertUtils.isTrue(childCount == 0, "请先删除子节点");

        if (category.getType().equals("todo")) {
            long count = todoService.count(Wrappers.<Todo>lambdaQuery().eq(Todo::getCategoryId, id));
            AssertUtils.isTrue(count == 0, "请先删除子待办");
        }

        boolean result = removeById(id);
        AssertUtils.isTrue(result, "分类删除失败");
    }
}